#include <unordered_map>
#include "scripting/script_task_object_pool.h"
#include "types/reflex.h"

namespace script
{
class ScriptTaskObjectPoolData
{
private:
    friend class ScriptTaskObjectPool;
    std::unordered_map<std::string, task::AbstractTaskConstPtr> defined_task_map;//task_variable:task object
    std::unordered_map<std::string, scheduler::AbstractSchedulerConstPtr> defined_scheduler_map;//scheduler_variable:scheduler
    std::string last_err_msg;
};
}

namespace script
{
script::ScriptTaskObjectPool::ScriptTaskObjectPool()
    : d(std::make_unique<ScriptTaskObjectPoolData>())
{

}
ScriptTaskObjectPool::~ScriptTaskObjectPool() = default;
bool ScriptTaskObjectPool::isObjectCreate(const std::string &task_variable)
{
    return d->defined_task_map.find(task_variable) != d->defined_task_map.end();
}
bool ScriptTaskObjectPool::createObject(const std::string &task_variable, const std::string &task_type, const std::string &task_name)
{
    if (task_variable.empty())
    {
        d->last_err_msg = "task variable cannot be empty";
        return false;
    }
    if (isObjectCreate(task_variable))
    {
        d->last_err_msg = "task variable [" + task_variable + "] is be create, do not create repeatedly";
        return false;
    }
    if (!reflex::TaskReflexManager::isTypeRegistered(task_type))
    {
        d->last_err_msg = "task type [" + task_type + "] is not be registered";
        return false;
    }
    auto task = reflex::TaskReflexManager::constructTask(task_type, task_name);
    d->defined_task_map.emplace(task_variable, std::move(task));
    return true;
}
bool ScriptTaskObjectPool::isFunctionCreate(const std::string &function_variable)
{
    return d->defined_scheduler_map.find(function_variable) != d->defined_scheduler_map.end();
}
bool ScriptTaskObjectPool::createFunction(const std::string &function_name, scheduler::AbstractSchedulerConstPtr &scheduler)
{
    if (function_name.empty())
    {
        d->last_err_msg = "function variable cannot be empty";
        return false;
    }
    if (isObjectCreate(function_name))
    {
        d->last_err_msg = "function variable [" + function_name + "] is the same as task name";
        return false;
    }
    if (isFunctionCreate(function_name))
    {
        d->last_err_msg = "function variable [" + function_name + "] is be create, do not create repeatedly";
        return false;
    }
    d->defined_scheduler_map.emplace(function_name, std::move(scheduler));
    return true;
}
std::optional<task::AbstractTaskConstPtr> ScriptTaskObjectPool::getTaskObject(const std::string &task_variable)
{
    if (!isObjectCreate(task_variable))
    {
        d->last_err_msg = "get task object fail, variable [" + task_variable + "] is not be defined";
        return std::nullopt;
    }
    return d->defined_task_map.at(task_variable);
}
std::optional<scheduler::AbstractSchedulerConstPtr> ScriptTaskObjectPool::getFunctionObject(const std::string &function_variable)
{
    if (!isFunctionCreate(function_variable))
    {
        d->last_err_msg = "get function object fail, variable [" + function_variable + "] is not be defined";
        return std::nullopt;
    }
    return d->defined_scheduler_map.at(function_variable);
}
std::string ScriptTaskObjectPool::getLastErrorMessage() const
{
    return d->last_err_msg;
}
std::shared_ptr<ScriptTaskObjectPool> ScriptTaskObjectPool::getTaskPoolPtr()
{
    return shared_from_this();
}
}
